<!--
 * @Author: zengwj
 * @Date: 2022-06-02 14:15:03
 * @LastEditors: zengwj
 * @LastEditTime: 2022-06-17 17:41:35
 * @Description:
-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
</head>

<body>
    <script>
        const PENDING = 'pending';
        const FULFILLED = 'fulfilled';
        const REJECTED = 'rejected';
        class MyPromise {
            status = PENDING
            value = null
            onFulfilledCallback = []
            onRejectedCallback = []
            constructor(executor) {
                try {
                    executor(this.resolve.bind(this), this.reject.bind(this))
                } catch (error) {
                    this.reject(error)
                }
            }
            static all(promises) {
                return new MyPromise((resolve, reject) => {
                    if (Array.isArray(promises)) {
                        let result = []
                        let count = 0
                        // 如果传入的参数是一个空的可迭代对象，则返回一个已完成（already resolved）状态的 Promise
                        if (promises.length === 0) {
                            return resolve(promises);
                        }
                        promises.forEach((item, index) => {
                            //判定参数是否为promise
                            if (item instanceof MyPromise) {
                                MyPromise.resolve(item).then(value => {
                                    count++
                                    result[index] = value
                                    count === promises.length && resolve(result)
                                }, reson => {
                                    /**
                                * 如果传入的 promise 中有一个失败（rejected），
                                * Promise.all 异步地将失败的那个结果给失败状态的回调函数，而不管其它 promise 是否完成
                                */
                                    reject(reson)
                                })
                            } else {
                                // 参数非Promise 原样返回 到数组里
                                count++
                                result[index] = item
                                count === promises.length && resolve(result)
                            }
                        })
                    } else {
                        return reject(new TypeError('Argument is not iterable'))
                    }
                })

            }
            static resolve(value) {
                // 如果这个值是一个 promise ，那么将返回这个 promise
                if (value instanceof MyPromise) {
                    return value
                } else if (value instanceof Object && 'then' in value) {
                    // 如果这个值是thenable（即带有`"then" `方法），返回的promise会“跟随”这个thenable的对象，采用它的最终状态；
                    return new myPromise((resolve, reject) => {
                        value.then(resolve, reject);
                    })
                }
                return new MyPromise((resolve) => {
                    resolve(value)
                })

            }
            resolve(value) {
                if (this.status === PENDING) {
                    this.status = FULFILLED
                    this.value = value
                    this.onFulfilledCallback.forEach(callback => {
                        callback(value)
                    });
                }
            }
            reject(reson) {
                if (this.status === PENDING) {
                    this.status = REJECTED
                    this.value = reson
                    this.onRejectedCallback.forEach(callback => {
                        callback(reson)
                    })
                }
            }
            then(onFulfilled, onRejected) {
                const promise2 = new MyPromise((resolve, reject) => {
                    const fulfilledMicrotask = () => {
                        queueMicrotask(() => {
                            try {
                                const x = onFulfilled(this.value)
                                resolvePromise(promise2, x, resolve, reject)
                            } catch (error) {
                                reject(error)
                            }
                        })
                    }
                    const rejectedMicrotask = () => {
                        // 创建一个微任务等待 promise2 完成初始化
                        queueMicrotask(() => {
                            try {
                                // 调用失败回调，并且把原因返回
                                const x = onRejected(this.value);
                                // 传入 resolvePromise 集中处理
                                resolvePromise(promise2, x, resolve, reject);
                            } catch (error) {
                                reject(error)
                            }
                        })
                    }
                    if (this.status === PENDING) {
                        this.onFulfilledCallback.push(fulfilledMicrotask)
                        this.onRejectedCallback.push(rejectedMicrotask)
                    }
                    else if (this.status === FULFILLED) {
                        fulfilledMicrotask()
                    } else if (this.status === REJECTED) {
                        rejectedMicrotask()
                    }
                })
                return promise2
            }
            finally(callback) {
                return this.then(callback, callback)
            }
            catch(onRejected) {
                return this.then(undefined, onRejected)
            }
        }

        function resolvePromise(promise2, x, resolve, reject) {
            // 如果相等了，说明return的是自己，抛出类型错误并返回
            if (promise2 === x) {
                return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
            }
            // 判断x是不是 MyPromise 实例对象
            if (x instanceof MyPromise) {
                // 执行 x，调用 then 方法，目的是将其状态变为 fulfilled 或者 rejected
                // x.then(value => resolve(value), reason => reject(reason))
                // 简化之后
                x.then(resolve, reject)
            } else {
                // 普通值
                resolve(x)
            }
        }
        // const promise1 = Promise.resolve(3);
        // const promise2 = 42;
        // const promise3 = new Promise((resolve, reject) => {
        //     setTimeout(() => {
        //         reject('foo')
        //     }, 1000);
        // });

        Promise.race([]).then((values) => {
            console.log(values);
        }, (reason) => {
            console.log(reason)
        });

    </script>
</body>

</html>